package com.xneure.database.sql;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.stereotype.Component;

import com.xneure.database.annotation.DataType;
import com.xneure.database.dao.DataBaseTable;
import com.xneure.database.dao.EntityProxy;
import com.xneure.database.metaobject.FieldMetaObject;
import com.xneure.database.metaobject.TableMetaObject;
import com.xneure.database.sql.handler.HandlerType;
import com.xneure.database.sql.handler.QueryHandler;
import com.xneure.database.sql.handler.SqlHandler;
import com.xneure.utils.JsonUtil;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.bean.BeanProcessor;

@Component
public class QueryMappingParser extends SqlMapping {
	public String qurey(Object obj, String where) {
		SqlHandler sqlHandler = getHandler(HandlerType.QUERY, obj.getClass());
		sqlHandler.resetParam();
		sqlHandler.build(obj);
		sqlHandler.addWhere(createWhere(obj, where));
		return sqlHandler.getSql();
	}

	protected String createWhere(Object obj, String where) {
		StringBuilder sb = new StringBuilder();
		TableMetaObject tmo = SqlHandler.getMetaObject(obj.getClass());
		tmo.getFields().forEach((k, e) -> {
			if (e.isIgnore() == false) {
				Object value = e.getValue(obj);
				if (null != value) {
					sb.append(e.getName()).append(" = ").append(value);
					sb.append(" AND ");
				}
			}
		});
		if (ObjectUtil.isNotNull(where)) {
			sb.append(where);
		} else {
			if (sb.length() > 1) {
				sb.setLength(sb.length() - 5);
			}
		}
		return sb.toString();
	}

	public String qurey(Object obj) {
		SqlHandler sqlHandler = getHandler(HandlerType.QUERY, obj.getClass());
		sqlHandler.resetParam();
		sqlHandler.addWhere(createWhere(obj, ""));
		sqlHandler.build(obj);
		return sqlHandler.getSql();
	}

	public String qurey(Class<?> cls, Object keyValue) {
		QueryHandler sqlHandler = (QueryHandler) getHandler(HandlerType.QUERY, cls);
		sqlHandler.resetParam();
		sqlHandler.build(cls);
		sqlHandler.addParam(sqlHandler.getKey(cls), SqlHandler.getValueConvert().sqlValue(keyValue));
		return sqlHandler.getSql();
	}

	public String qureyByWhere(Class<?> cls, String where) {
		QueryHandler sqlHandler = (QueryHandler) getHandler(HandlerType.QUERY, cls);
		sqlHandler.resetParam();
		sqlHandler.build(cls);
		sqlHandler.addWhere(where);
		return sqlHandler.getSql();
	}

	public <T> T toObject(Class<T> cls, Map<String, Object> res) {
		return toObject(cls, res, null);
	}

	public <T> T toObject(Class<T> cls, Map<String, Object> res, Map<String, FieldMetaObject> fs) {
		EntityProxy entityProxy = new EntityProxy();
		T obj = ObjectUtil.objectProxy(cls, entityProxy);
//		T obj = ObjectUtil.newInstance(cls);
		if (DataBaseTable.class.isAssignableFrom(cls)) {
			ObjectUtil.modifyFieldValue(obj, "source", res);
		}
		BeanProcessor bp = new BeanProcessor(obj);
		ValueConvert vc = SqlHandler.getValueConvert();
		if (null == fs) {
			TableMetaObject tmo = SqlHandler.getMetaObject(cls);
			fs = tmo.getFields();
		}
		for (Entry<String, FieldMetaObject> ent : fs.entrySet()) {
			FieldMetaObject fieldMetaObject = ent.getValue();
			Field field = fieldMetaObject.getField();
			if (res.containsKey(ent.getKey())) {
				Object object = res.get(ent.getKey());
				if (null != object) {
					if (null != fieldMetaObject.getAnnotation()
							&& fieldMetaObject.getAnnotation().dataType() == DataType.JSON) {
						bp.setValue(field.getName(), JsonUtil.toObject(object.toString(), field.getType()));
					} else {
						bp.setValue(field.getName(), vc.objectValue(field, object));
					}
				}
			} else {
				if (DataBaseTable.class.isAssignableFrom(getTargetType(field, fieldMetaObject.getAnnotation()))) {
					if (null != fieldMetaObject.getAnnotation() && null != fieldMetaObject.getAnnotation().relation()) {
						entityProxy.addMonitor(ent.getKey(), fieldMetaObject);
//						Object val = ObjectUtil.fieldProxy(field.getType(),new DBLazyLoader(obj,fieldMetaObject));
//						bp.setValue(field.getName(),vc.objectValue(field,val));
					}
				}
			}
		}
		return obj;
	}
}
